package com.vict.dao;

import com.vict.bean.TaskExecuteInstance;
import com.vict.util.ObjectUtil;
import com.vict.util.TimeUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.*;
import java.util.*;

@Slf4j
@Component
public class TaskExecuteInstanceDao {

    public DataSource dataSource;

    @Autowired
    private AutoApiSqlMapper autoApiSqlMapper;

    @SneakyThrows
    public List<String> selectAllType(){
        List<String> allType = new ArrayList<>();

        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try{
            String sql = "select distinct type as type from task_execute_instance;";
            statement = this.dataSource.getConnection().prepareStatement(sql);
            resultSet = statement.executeQuery();

            while(resultSet.next()){
                String type = resultSet.getObject("type", String.class);
                allType.add(type);
            }
            return allType;
        }finally{
            if(statement != null){
                statement.close();
            }
            if(resultSet != null){
                resultSet.close();
            }
        }
    }

    @SneakyThrows
    public List<String> selectAllServerName(){
        List<String> allServerName = new ArrayList<>();

        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try{
            String sql = "select distinct serverName as serverName from task_execute_instance;";
            statement = this.dataSource.getConnection().prepareStatement(sql);
            resultSet = statement.executeQuery();

            while(resultSet.next()){
                String type = resultSet.getObject("serverName", String.class);
                allServerName.add(type);
            }
            return allServerName;
        }catch(Exception e){
            log.error("", e);
            return allServerName;
        }finally{
            if(statement != null){
                statement.close();
            }
            if(resultSet != null){
                resultSet.close();
            }
        }
    }

    @SneakyThrows
    public TaskExecuteInstance selectById(String taskExecuteInstanceID, Connection connection){
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try{
            String sql = "select * from task_execute_instance where taskExecuteInstanceID = ? ;";
            statement = connection.prepareStatement(sql);
            statement.setString(1, taskExecuteInstanceID);
            resultSet = statement.executeQuery();
            if(resultSet.next()){
                TaskExecuteInstance taskExecuteInstance = new TaskExecuteInstance();

                taskExecuteInstance.setTaskExecuteInstanceID(resultSet.getObject("taskExecuteInstanceID", String.class));
                taskExecuteInstance.setServerName(resultSet.getObject("serverName", String.class));
                taskExecuteInstance.setServerId(resultSet.getObject("serverId", String.class));
                taskExecuteInstance.setType(resultSet.getObject("type", String.class));
                taskExecuteInstance.setStatus(resultSet.getObject("status", Integer.class));
                taskExecuteInstance.setExecuteCount(resultSet.getObject("executeCount", Integer.class));
                taskExecuteInstance.setActionTime(resultSet.getObject("actionTime", Timestamp.class));
                taskExecuteInstance.setExecuteJSON(resultSet.getObject("executeJSON", String.class));
                taskExecuteInstance.setStContext(resultSet.getObject("stContext", String.class));
                taskExecuteInstance.setLinkTaskExecuteInstanceID(resultSet.getObject("linkTaskExecuteInstanceID", String.class));

                return taskExecuteInstance;
            }
            return null;
        }finally{
            if(statement != null){
                statement.close();
            }
            if(resultSet != null){
                resultSet.close();
            }
        }
    }

    @SneakyThrows
    public void updateById(TaskExecuteInstance taskExecuteInstance, Connection connection){
        PreparedStatement statement = null;
        try{
            String sql =
                    "UPDATE `task_execute_instance` " +
                            "SET " +
                            "  `serverName` = ?, " +
                            "  `serverId` = ?, " +
                            "  `type` = ?, " +
                            "  `status` = ?, " +
                            "  `executeCount` = ?, " +
                            "  `actionTime` = ?, " +
                            "  `executeJSON` = ?, " +
                            "  `stContext` = ?, " +
                            "  `linkTaskExecuteInstanceID` = ? " +
                            "WHERE " +
                            "  `taskExecuteInstanceID` = ? ;";

            statement = connection.prepareStatement(sql);
            statement.setObject(1, taskExecuteInstance.getServerName(), Types.VARCHAR);
            statement.setObject(2, taskExecuteInstance.getServerId(), Types.VARCHAR);
            statement.setObject(3, taskExecuteInstance.getType(), Types.VARCHAR);
            statement.setObject(4, taskExecuteInstance.getStatus(), Types.INTEGER);
            statement.setObject(5, taskExecuteInstance.getExecuteCount(), Types.INTEGER);
            statement.setObject(6, taskExecuteInstance.getActionTime(), Types.TIMESTAMP);
            statement.setObject(7, taskExecuteInstance.getExecuteJSON(), Types.VARCHAR);
            statement.setObject(8, taskExecuteInstance.getStContext(), Types.VARCHAR);
            statement.setObject(9, taskExecuteInstance.getLinkTaskExecuteInstanceID(), Types.INTEGER);
            statement.setObject(10, taskExecuteInstance.getTaskExecuteInstanceID(), Types.INTEGER);

            statement.executeUpdate();
        }finally{
            if(statement != null){
                statement.close();
            }
        }
    }

    @SneakyThrows
    public void deleteById(String taskExecuteInstanceID, Connection connection){
        PreparedStatement statement = null;
        try{
            String sql = "delete from `task_execute_instance` where taskExecuteInstanceID = ?";
            statement = connection.prepareStatement(sql);
            statement.setString(1, taskExecuteInstanceID);

            statement.executeUpdate();
        }catch(Exception e){
            if(statement != null){
                statement.close();
            }
        }
    }

    @SneakyThrows
    public void insert(TaskExecuteInstance taskExecuteInstance, Connection connection){
        PreparedStatement statement = null;
        try{
            String sql =
                    "INSERT INTO `task_execute_instance` ( " +
                    "  `taskExecuteInstanceID`, " +
                    "  `serverName`, " +
                    "  `serverId`, " +
                    "  `type`, " +
                    "  `status`, " +
                    "  `executeCount`, " +
                    "  `actionTime`, " +
                    "  `executeJSON`, " +
                    "  `stContext`, " +
                    "  `linkTaskExecuteInstanceID` " +
                    ") VALUES ( " +
                    "  ?, " +
                    "  ?, " +
                    "  ?, " +
                    "  ?, " +
                    "  ?, " +
                    "  ?, " +
                    "  ?, " +
                    "  ?, " +
                    "  ?, " +
                    "  ? " +
                    ");";

            statement = connection.prepareStatement(sql);


            statement.setObject(1, taskExecuteInstance.getTaskExecuteInstanceID(), Types.VARCHAR);
            statement.setObject(2, taskExecuteInstance.getServerName(), Types.VARCHAR);
            statement.setObject(3, taskExecuteInstance.getServerId(), Types.VARCHAR);
            statement.setObject(4, taskExecuteInstance.getType(), Types.VARCHAR);
            statement.setObject(5, taskExecuteInstance.getStatus(), Types.INTEGER);
            statement.setObject(6, taskExecuteInstance.getExecuteCount(), Types.INTEGER);
            statement.setObject(7, taskExecuteInstance.getActionTime(), Types.TIMESTAMP);
            statement.setObject(8, taskExecuteInstance.getExecuteJSON(), Types.VARCHAR);
            statement.setObject(9, taskExecuteInstance.getStContext(), Types.VARCHAR);
            statement.setObject(10, taskExecuteInstance.getLinkTaskExecuteInstanceID(), Types.VARCHAR);

            statement.executeUpdate();
        }finally{
            if(statement != null){
                statement.close();
            }
        }
    }

    @SneakyThrows
    public List<TaskExecuteInstance> selectList(String type,
                                                String serverName,
                                                String id,
                                                String serverId,
                                                String status,
                                                String time1,
                                                String time2,
                                                int pageNum, // 1 2 3
                                                int length){
        if(pageNum == 0){
            pageNum = 1;
        }

        Map<String, String> params = new HashMap<>();
        params.put("type", type);
        params.put("serverName", serverName);
        params.put("id", id);
        params.put("serverId", serverId);
        params.put("status", status);
        params.put("time1", time1);
        params.put("time2", time2);
        params.put("limit", (pageNum - 1) * length + "");
        params.put("length", length + "");
        String sql = "<script>\n" +
                "        select * from task_execute_instance\n" +
                "        <where>\n" +
                "            <if test=\"type != null\">\n" +
                "                and type = #{type}\n" +
                "            </if>\n" +
                "            <if test=\"serverName != null\">\n" +
                "                and serverName = #{serverName}\n" +
                "            </if>\n" +
                "            <if test=\"id != null\">\n" +
                "                and taskExecuteInstanceID = #{id}\n" +
                "            </if>\n" +
                "            <if test=\"serverId != null\">\n" +
                "                and serverId = #{serverId}\n" +
                "            </if>\n" +
                "            <if test=\"status != null\">\n" +
                "                and status = #{status}\n" +
                "            </if>\n" +
                "            <if test=\"time1 != null\">\n" +
                "                and #{time1} <![CDATA[<=]]> actionTime\n" +
                "            </if>\n" +
                "            <if test=\"time2 != null\">\n" +
                "                and actionTime <![CDATA[<=]]> #{time2}\n" +
                "            </if>\n" +
                "        </where>\n" +
                "        order by actionTime desc\n" +
                "        <if test=\"limit != null\">\n" +
                "            limit ${limit}, ${length}\n" +
                "        </if>" +
                "</script>";
        List<Map> maps = autoApiSqlMapper.selectList(sql, params, Map.class);

        List<TaskExecuteInstance> taskExecuteInstances = new ArrayList<>();
        for(Map map : Optional.ofNullable(maps).orElse(new ArrayList<>())){
            TaskExecuteInstance taskExecuteInstance = new TaskExecuteInstance();

            taskExecuteInstance.setTaskExecuteInstanceID(Optional.ofNullable(map).map(o-> o.get("taskExecuteInstanceID")).map(o-> o.toString()).orElse(null));
            taskExecuteInstance.setServerName(Optional.ofNullable(map).map(o-> o.get("serverName")).map(o-> o.toString()).orElse(null));
            taskExecuteInstance.setServerId(Optional.ofNullable(map).map(o-> o.get("serverId")).map(o-> o.toString()).orElse(null));
            taskExecuteInstance.setType(map.get("type").toString());
            taskExecuteInstance.setStatus(Integer.parseInt(map.get("status").toString()));
            taskExecuteInstance.setExecuteCount(Integer.parseInt(map.get("executeCount").toString()));
            taskExecuteInstance.setActionTime(map.get("actionTime") == null ? null : new Timestamp(TimeUtil.getTime(null, map.get("actionTime").toString())));
            taskExecuteInstance.setExecuteJSON(Optional.ofNullable(map).map(o-> o.get("executeJSON")).map(o-> o.toString()).orElse(null));
            taskExecuteInstance.setStContext(Optional.ofNullable(map).map(o-> o.get("stContext")).map(o-> o.toString()).orElse(null));
            taskExecuteInstance.setLinkTaskExecuteInstanceID(map.get("linkTaskExecuteInstanceID") == null ? null : map.get("linkTaskExecuteInstanceID").toString());

            taskExecuteInstances.add(taskExecuteInstance);
        }

        return taskExecuteInstances;
    }

    public void updateStatus(String id, Integer status){
        Map<String, String> params = new HashMap<>();
        params.put("id", id);
        params.put("status", status.toString());
        String sql = "<script>\n" +
                "update task_execute_instance set status = #{status} where taskExecuteInstanceID = #{id}" +
                "</script>";
        autoApiSqlMapper.update(sql, params);
    }

    public void updateTime(String id, String time){
        Map<String, String> params = new HashMap<>();
        params.put("id", id);
        params.put("time", time);
        String sql = "<script>\n" +
                "update task_execute_instance set actionTime = #{time} where taskExecuteInstanceID = #{id}" +
                "</script>";
        autoApiSqlMapper.update(sql, params);
    }

    public void updateServerId(String id, String serverId){
        Map<String, String> params = new HashMap<>();
        params.put("id", id);
        params.put("serverId", serverId);
        String sql = "<script>\n" +
                "update task_execute_instance set serverId = #{serverId} where taskExecuteInstanceID = #{id}" +
                "</script>";
        autoApiSqlMapper.update(sql, params);
    }

    public void updateExecuteCount(String id, String executeCount){
        Map<String, String> params = new HashMap<>();
        params.put("id", id);
        params.put("executeCount", executeCount);
        String sql = "<script>\n" +
                "update task_execute_instance set executeCount = #{executeCount} where taskExecuteInstanceID = #{id}" +
                "</script>";
        autoApiSqlMapper.update(sql, params);
    }


    @SneakyThrows
    public List<TaskExecuteInstance> selectBatchIds(List<String> ids, Connection connection){
        PreparedStatement statement = null;
        ResultSet resultSet = null;

        List<TaskExecuteInstance> list = new ArrayList<>();
        if(ids == null || ids.size() == 0){
            return list;
        }

        try{

            String sql = "select * from task_execute_instance where taskExecuteInstanceID in (";
            for(int i = 0 ; i < ids.size(); i++){
                if(i != ids.size() - 1){
                    sql += "?, ";
                }else{
                    sql += "?";
                }
            }
            sql += ");";

            statement = connection.prepareStatement(sql);

            for(int i = 0 ; i < ids.size(); i++){
                statement.setString(i + 1, ids.get(i));
            }

            resultSet = statement.executeQuery();

            while(resultSet.next()){
                TaskExecuteInstance taskExecuteInstance = new TaskExecuteInstance();

                taskExecuteInstance.setTaskExecuteInstanceID(resultSet.getObject("taskExecuteInstanceID", String.class));
                taskExecuteInstance.setServerName(resultSet.getObject("serverName", String.class));
                taskExecuteInstance.setServerId(resultSet.getObject("serverId", String.class));
                taskExecuteInstance.setType(resultSet.getObject("type", String.class));
                taskExecuteInstance.setStatus(resultSet.getObject("status", Integer.class));
                taskExecuteInstance.setExecuteCount(resultSet.getObject("executeCount", Integer.class));
                taskExecuteInstance.setActionTime(resultSet.getObject("actionTime", Timestamp.class));
                taskExecuteInstance.setExecuteJSON(resultSet.getObject("executeJSON", String.class));
                taskExecuteInstance.setStContext(resultSet.getObject("stContext", String.class));
                taskExecuteInstance.setLinkTaskExecuteInstanceID(resultSet.getObject("linkTaskExecuteInstanceID", String.class));

                list.add(taskExecuteInstance);
            }
        }finally{
            if(statement != null){
                statement.close();
            }
            if(resultSet != null){
                resultSet.close();
            }
        }
        return list;
    }

    @SneakyThrows
    public void updateStatusById(String id,
                                 Integer status,
                                 Connection connection){

        PreparedStatement statement = null;
        try{
            statement = connection.prepareStatement("update task_execute_instance set status = ? where taskExecuteInstanceID = ? and status != 2 and status != 3");
            statement.setObject(1, status, Types.INTEGER);
            statement.setObject(2, id, Types.VARCHAR);
            statement.executeUpdate();
        }finally{
            if(statement != null){
                statement.close();
            }
        }
    }

    @SneakyThrows
    public void updateExecuteCount(String id,
                                   Integer executeCount,
                                   Connection connection){

        PreparedStatement statement = null;
        try{
            statement = connection.prepareStatement("update task_execute_instance set executeCount = ? where taskExecuteInstanceID = ?");
            statement.setObject(1, executeCount, Types.INTEGER);
            statement.setObject(2, id, Types.VARCHAR);
            statement.executeUpdate();
        }finally{
            if(statement != null){
                statement.close();
            }
        }
    }

    @SneakyThrows
    public void deleteByLinkId(String linkID,
                               Connection connection){
        PreparedStatement statement = null;
        try{
            statement = connection.prepareStatement("delete from task_execute_instance where linkTaskExecuteInstanceID = ? and status = 0");
            statement.setObject(1, linkID, Types.VARCHAR);
            statement.executeUpdate();
        }finally{
            if(statement != null){
                statement.close();
            }
        }
    }
}
